#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <limits.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <pthread.h>
#include <fcntl.h>
#include "type.h"
#include "xml_conf.h"
#include "cli.h"
#include "buf_misc.h"
#include "cli_main.h"
#include "fastlz.h"
#include "WDAuthSDK.h"
#include "./../3rdparty/include/openssl/des.h"
#include "./../flexapi/legu_sh/csmtpmsg.h"
#include "./../flexapi/xinan_hn/externalMsgApi4XA.h"
#include "./../flexapi/zhongdun_xa/zhongdun_xa_msgHandler.h"
#include "./../flexapi/nanfei/nanfeiManager.h"

#ifdef IF_APP_UNIT_TEST
#include "cmd.h"
#endif
static I32 disable_auth = 0;
static pthread_t cli_thread;
static pthread_t cli_udp_thread;
static pthread_mutex_t cli_mutex;
static bool cliThreadIsOk = false;
static I32 sock_mng = -1;
static I32 mng_status = MNG_SERVER_STATUS_DISCONNECTED;
static I32 sock_data = -1;
static I32 data_status = DATA_SERVER_STATUS_DISCONNECTED;
extern I8 *up_tmp;
static I8 *bufSnd = NULL;
static I32 udpSock = -1;
static char eth1Mac[20] = {0};
#ifdef MODULE_TEST
static bool testCliThread = false;
void setTestCliThread()
{
    testCliThread = true;
}

#endif




__inline I32 cli_set_mng_status(I32 status)
{
    if (status < MNG_SERVER_STATUS_DISCONNECTED || status > MNG_SERVER_STATUS_CONNECTED) 
	{
        return -1;
    }
    mng_status = status;
	
    return 0;
}
__inline I32 cli_get_mng_status(void)
{
    return mng_status;

}
__inline I32 cli_get_data_status(void)
{
    return data_status;

}

__inline I32 cli_set_data_status(I32 status)
{
    if (status < DATA_SERVER_STATUS_DISCONNECTED || status > DATA_SERVER_STATUS_CONNECTED) 
    {
        return -1;
    }
    data_status = status;
	
    return 0;
}

I32 cli_sock_is_mng(I32 sock)
{
    if (strcmp(dev_conf.dev.protocol, NANFEI) != 0)
    {
        if(sock == sock_mng) 
        {
            return IF_APP_OK;
        }

    }
    else
    {
        return IF_APP_OK;
    }
    return IF_APP_ERROR;
}

I32 cli_sock_is_data(I32 sock)
{
	if(sock == sock_data) 
	{
		return IF_APP_OK;
	}

    return IF_APP_ERROR;

}

I8 *get_host_by_server(I8 *server)
{
    struct hostent *he;
    struct in_addr **addr_list;
    if ((he = gethostbyname(server)) == NULL) {  
        cli_app_log(CLI_LOG_WARNING, "can not get host from server %s erro is %s \n", server,  strerror(errno));
        return NULL;
    }
    I32 i = 0;
    addr_list = (struct in_addr **)he->h_addr_list;
    for(i = 0; addr_list[i] != NULL; i++) {
        cli_app_log(CLI_LOG_INFO, "server list %s \n", inet_ntoa(*addr_list[i]));
    }
    return inet_ntoa(*addr_list[0]);
}

static I32 cli_create_tcp_socket_to(I32 timeout, I32 srv, I8 * addr, I32 port)
{
    I32 sockfd;
    I32 fnctl_tmp, select_tmp;
    struct sockaddr_in server_addr;
    fd_set set;
    struct timeval connect_tv;
    I32 error;
    socklen_t len = sizeof(error);

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
	{
        cli_app_log(CLI_LOG_CRITICAL, 
					"Create socket Error:%s\n",
                    strerror(errno));
        return -1;
    }
	
    fnctl_tmp = fcntl(sockfd, F_GETFL);
    fcntl(sockfd, F_SETFL, fnctl_tmp | O_NONBLOCK);

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    if (get_host_by_server(addr) == NULL)
        return -1;
	cli_app_log(CLI_LOG_INFO, "port %d  srv %s\n", port, addr);
    if (inet_pton(AF_INET, get_host_by_server(addr), &server_addr.sin_addr) <= 0) 
	{
        cli_app_log(CLI_LOG_CRITICAL,
                    "Address translation fail, remote addr %s, remote port %d\n",
                    addr, port);
		
        close(sockfd);
        return -1;
    }

    if (connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == 0) 
	{
        cli_app_log(CLI_LOG_CRITICAL, 
					"Connect to  Error:%s  error code is %d\n",
                    strerror(errno), errno);
		
        close(sockfd);
        if (errno != ECONNREFUSED)
        {
            return -1;
        }
        else
        {
            return IF_APP_CONNECT_REFUSED;
        }
    }

	
    if (errno != EINPROGRESS) 
    {
        cli_app_log(CLI_LOG_CRITICAL, 
					"connect is ok Connect Error:%s\n", 
					strerror(errno));
        close(sockfd);
        return -1;
    }

    FD_ZERO(&set);
    FD_SET(sockfd, &set);
    connect_tv.tv_usec = 0;
    connect_tv.tv_sec = timeout;
	
    select_tmp = select(sockfd + 1, NULL, &set, NULL, &connect_tv);

    if (select_tmp == -1) 
	{
        cli_app_log(CLI_LOG_CRITICAL, 
					"Connect Error:%s\n", "select failed.");
		
        close(sockfd);
        return -1;

    } 
    else if (select_tmp == 0)
	{
        cli_app_log(CLI_LOG_CRITICAL, 
					"Connect Error:%s\n", "timed out.");
		
        close(sockfd);
        return -1;

    }

    if (FD_ISSET(sockfd, &set)) 
    {
        if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) 
        {
            cli_app_log(CLI_LOG_CRITICAL,
						"Connect Error:%s\n",
                        "getsockopt failed.");
			
            close(sockfd);
            return -1;
        }

        if (error == ETIMEDOUT) 
        {
            cli_app_log(CLI_LOG_CRITICAL, 
						"Connect Error11:%s\n", 
						"timed out.");
			
            close(sockfd);
            return -1;

        }

        if (error == ECONNREFUSED) 
        {
            cli_app_log(CLI_LOG_CRITICAL, 
						"Connect Error:%s error code is %d\n",
                        strerror(error), error);
			
            close(sockfd);
            return IF_APP_CONNECT_REFUSED ;

        }
        if (error != 0)
        {
            cli_app_log(CLI_LOG_CRITICAL, 
						"Connect Error:%s %d\n",
                        strerror(error), error);
			
            close(sockfd);
            return -1;

        }

    }
	
    fcntl(sockfd, F_SETFL, fnctl_tmp | O_NONBLOCK);

    cli_app_log(CLI_LOG_NOTICE, 
				"Connect to address %s:%d successed\n", 
				addr, port);

	if (srv == CLI_SRV_DATA) 
	{
        sock_data = sockfd;
        I32 SndBuf=65535;
        if (setsockopt(sock_data, SOL_SOCKET, SO_SNDBUF, (const char *)&SndBuf, sizeof(I32)) < 0)
        {
            cli_app_log(CLI_LOG_ERROR, "setsockopt error %d %s\n", errno, strerror(errno));
        }
    } 
	else if (srv == CLI_SRV_MNG) 
	{
        sock_mng = sockfd;
    } 
	else 
	{
        close(sockfd);
        sockfd = -1;
    }
	
    return sockfd;
}

I32 cli_destroy_tcp_socket(I32 fd)
{
    if (fd == sock_mng || fd == CLI_TO_SRV_ALL_MASK) 
	{
        cli_app_log(CLI_LOG_WARNING, "close sock mng----- %d \n", sock_mng);
        if (sock_mng != -1)
            close(sock_mng);
        sock_mng = -1;
        
        mng_status = MNG_SERVER_STATUS_DISCONNECTED;

    }
	
    if (fd == sock_data || fd == CLI_TO_SRV_ALL_MASK) 
    {
        cli_app_log(CLI_LOG_WARNING, "close sock data ---- sock_data %d \n", sock_data);
        if (sock_data != -1)
            close(sock_data);

        sock_data = -1;
       
        data_status = DATA_SERVER_STATUS_DISCONNECTED;

    }

    return 0;
}

static I32 cli_compress_data(I8 * data, I32 data_len, I8 * buf)
{
    int len;
	
    len = fastlz_compress(data, data_len, buf);
	
    if (len > 65535) 
    {
        cli_app_log(CLI_LOG_ERROR, 
					"DEBUG: Compress error!\n");
        len = 0;
    } 
	else if(len <= 0) 
    {
	    cli_app_log(CLI_LOG_ERROR, 
					"DEBUG: Compress error!\n");
        return IF_APP_ERROR;
	}
	cli_app_log(CLI_LOG_INFO, "compress len ====== %d \n", len);
    return len;
}

static I32 cli_decompress_data(I8 * data, I32 data_len, I8 * buf)
{
    I32 len;

    len = fastlz_decompress(data, data_len, buf, BUFFER_BLOCK_SIZE - 1);
    buf[len] = 0;

    if (len == 0) 
	{
        cli_app_log(CLI_LOG_ERROR, 
					"Dcompress error, source: %s\n", data);

        return 0;
    }

    return len;
}

//todo: add handshark and real encrypt code here.
static I32 cli_encrypt_data(I8 * data, I32 data_len, I8 * out, size_t * out_len)
{
    int rst = WD_AES_Encrypt(data, data_len, out, out_len);
	if (rst != WD_SUCESS) 
	{
        cli_app_log(CLI_LOG_ERROR,"encrypt data faild,rst == %d\n", rst);	
	    return IF_APP_ERROR;
	}
	return 0;

}

//todo: add handshark and real decrypt code here.
static I32 cli_decrypt_data(I8 * data, I32 data_len, I8 * out, size_t * out_len)
{
	
    int rst = WD_AES_Decryption((const I8 *)data, data_len, out, out_len);
    if (rst == WD_SUCESS) 
    {
        return 0;
    }
    cli_app_log(CLI_LOG_ERROR, "Unencrypted error rst ==%d\n", rst);
    return IF_APP_ERROR;
}
//if send_skey == 1,at this time send the authentication code,we don't need encrypt data
I32 cli_send_to_tcp(I32 fd, I8 * data, I32 len, I32 send_skey)
{


    I32 sent = 0, len_tmp = 0;
    I8 *buf;
    buf = NULL;
    size_t out_len = 0;
    I32 err = 0;
	
#ifdef IF_APP_UNIT_TEST
    if (len < 2000) 
	{
        cli_app_log(CLI_LOG_INFO,
                    "Unit test: send to socket %d, len %d, data: %s\n", 
                    fd, len, data);
    }
#endif
    if (len <= 0) 	
	{
        return IF_APP_ERROR;
    }

    if (fd > 0) 
    {
	    if (fd == sock_mng) 
		{
            err = CLI_SOCK_ERR_MNG;
        } 
	    else if ((fd == sock_data)) 
        {
            if ((send_skey == 0) && ((disable_auth == 0) || (disable_auth == 2)))
            {
                len = cli_compress_data(data, len, up_tmp);
                data = up_tmp;
            }
            err = CLI_SOCK_ERR_DATA;
			
        } 
        else
            return IF_APP_ERROR;
        if (len > 8000)
            buf = bufSnd;
        else
            buf = buffer_allocate();
        if (buf == NULL) 
		{
            cli_app_log(CLI_LOG_ERROR, 
						"send to tcp: get buffer fail\n");
            return IF_APP_ERROR;
        }
		if ((send_skey == 0) && (disable_auth == 0))
		{
	
            if (cli_encrypt_data(data, len, buf, &out_len) < 0) 
			{
                if (len > 8000)
                {
                    memset(buf, 0, 65535);
                    buf = NULL;
                }
                else
                    buffer_free(buf);
            	//here, if encrypt error, think it is a scoket auth error.
            	event_queue_add(IF_APP_EVENT_CLI_STOP, 0, 0, NULL);
                return IF_APP_ERROR;
            }
        } 
        else
        {
            memcpy(buf,data,len);
            out_len = len;
		}
			
        while (sent < out_len) 
		{
            len_tmp = write(fd, buf + sent, out_len - sent);
            if (len_tmp < 0) 
			{
                if ( len_tmp == -1 && errno == EINTR )
                    continue;

                if (errno == EAGAIN)
                {
                    cli_app_log(CLI_LOG_ERROR, "tcp send buf is full %s\n ", strerror(errno));
                }

                if (len > 8000)
                {
                    memset(buf, 0, 65535);
                    buf = NULL;
                }      
                else
                    buffer_free(buf);
                cli_app_log(CLI_LOG_CRITICAL, 
							"send to tcp socket %d failed\n", fd);
                event_queue_add(IF_APP_EVENT_CLI_STOP, err, 0,  NULL);
                return IF_APP_ERROR;
            }
			
            sent += len_tmp;
        }
        if (len > 8000)
        {
            memset(buf, 0, 65535);
            buf = NULL;
        }
        else
            buffer_free(buf);

    } 
    else 
    {
        return IF_APP_ERROR;
    }

    return IF_APP_OK;
}

//might be broadcast, not handle broadcast at this time.
I32 cli_send_to_data(I8 * data, I32 len)
{
    if (strcmp(dev_conf.dev.protocol, ZHONGDUN) != 0)
    {
        return cli_send_to_tcp(sock_data, data, len, 0);
    }
    else
    {
        I8 *buf = buffer_allocate();
        I32 bufLen = BUFFER_BLOCK_SIZE;
        if (buf == NULL)
        {
            cli_app_log(CLI_LOG_CRITICAL, 
					 "send to tcp: get buffer \n");
            return 0;
        }
        sendMsgToZhongdunXa(IF_APP_EVENT_DATA_SERVER, data, len, buf, &bufLen);
        bufLen = cli_send_to_tcp(sock_data, buf, bufLen, 0);
        buffer_free(buf);
        return bufLen;

    }
}

I32 send_imsi_data(bool isMng, I8 *record, I8 *buf)
{
    I32 len = BUFFER_BLOCK_SIZE;

    if (strcmp(dev_conf.dev.protocol, LEGU) == 0)
    {
        sendMsgToLeGuServer(IF_APP_EVENT_DATA_SERVER, (const char *)record, (ssize_t)0, buf, (ssize_t *)&len);
    }
    else if(strcmp(dev_conf.dev.protocol, ZHONGDUN) == 0)
    {
        if (isMng)
            sendMsgToZhongdunXa(IF_APP_EVENT_IMSI_MNG, (const char *)record, (ssize_t)0, buf, (ssize_t *)&len);
        else
            sendMsgToZhongdunXa(IF_APP_EVENT_IMSI_DATA, (const char *)record, (ssize_t)0, buf, (ssize_t *)&len);
    }
    if (isMng)
        cli_send_to_tcp(sock_mng, buf, len, 0);  
    else
        cli_send_to_tcp(sock_data, buf, len, 0);   
    return 0;
}

//might be broadcast, not handle broadcast at this time.
I32 cli_send_to_mng(I8 * data, I32 len)
{
    if (strcmp(dev_conf.dev.protocol, CAIPIN) == 0 || strcmp(dev_conf.dev.protocol, ZHIHUI) == 0 
        || strcmp(dev_conf.dev.protocol, KUANGUANG) == 0 || strcmp(dev_conf.dev.protocol, CAIPINNEW) == 0 
        || strcmp(dev_conf.dev.protocol, HUANSHUO) == 0 || strcmp(dev_conf.dev.protocol, WANGXUN) == 0
        || strcmp(dev_conf.dev.protocol, RENZIXING) == 0 || strcmp(dev_conf.dev.protocol, FENGHUO) == 0
        || strcmp(dev_conf.dev.protocol, JINFENG) == 0 || strcmp(dev_conf.dev.protocol, GAOKE) == 0
        || strcmp(dev_conf.dev.protocol, BAIZHUO) == 0 || strcmp(dev_conf.dev.protocol, LOCATION) == 0
        || strcmp(dev_conf.dev.protocol, ZISHUO) == 0)
    {
        return cli_send_to_tcp(sock_mng, data, len, 0);
    }
    else
    {
        I8 *buf = buffer_allocate();
        I32 bufLen = BUFFER_BLOCK_SIZE;
        if (buf == NULL)
        {
            cli_app_log(CLI_LOG_CRITICAL, 
					 "send to tcp: get buffer \n");
            return 0;
        }
		
		if(strcmp(dev_conf.dev.protocol, LEGU) == 0)
		{
            sendMsgToLeGuServer(IF_APP_EVENT_MNG_SERVER, data, len, buf, &bufLen);
		}
        else if(strcmp(dev_conf.dev.protocol, ZHONGDUN) == 0)
        {
            sendMsgToZhongdunXa(IF_APP_EVENT_MNG_SERVER, data, len, buf, &bufLen);
        }
		else if(strcmp(dev_conf.dev.protocol, XINAN) == 0)
		{		
            bufLen = 0;
  		    sendMsgToXinAnServer(data, len, buf, &bufLen);
            cli_app_log(CLI_LOG_INFO, "send msg to xinan server len is %d \n", bufLen);
            buffer_dump_log(buf, bufLen, CLI_LOG_DEFAULT);
		}
        else if (strcmp(dev_conf.dev.protocol, NANFEI) == 0)
        {
            
            cli_app_log(CLI_LOG_INFO, "send msg buf %s \n", data);
            bufLen = 0;
            sendMsgToNanfei(data, len, buf, &bufLen);
            sendHeartBeat(atoi(dev_conf.auth.port), buf, bufLen);
            buffer_free(buf);
            cli_app_log(CLI_LOG_INFO, "send buf len %d \n", bufLen);
            return bufLen;
            
        }
		else
		{
            buffer_free(buf);
		    return 0;
		}
		
        bufLen = cli_send_to_tcp(sock_mng, buf, bufLen, 0);
        buffer_free(buf);
        return bufLen;
    }

    return 0;
}

static I32 rcv_from_tcp(I32 fd, I8 ** data)
{
    I32 rcv = 0;
    size_t out_len = 0;
    I8 *buf, *buf_out;
    buf = buffer_allocate();
 
    if (buf == NULL) 
	{
        cli_app_log(CLI_LOG_CRITICAL, 
					"receive from tcp: get buffer fail1\n");
        return 0;
    }
	
    buf_out = buffer_allocate();

    if (buf_out == NULL) 
	{
        cli_app_log(CLI_LOG_CRITICAL, 
					"receive from tcp: get buffer fail2\n");
        buffer_free(buf);
        return 0;
    }

    do 
    {
        rcv = read(fd, buf, BUFFER_BLOCK_SIZE);
    } while( (rcv == -1) && (errno == EINTR));

    if (rcv < 0) 
	{
        cli_app_log(CLI_LOG_CRITICAL, 
					"socket rcv fail fd %d, ret %d\n", 
					fd, rcv);
    } 
	else if ((rcv > 0) && (disable_auth == 0) && (strstr(buf, "Welecome") == NULL) && (strstr(buf, "Welcome") == NULL)) 
	{
        if (cli_decrypt_data(buf, rcv, buf_out, &out_len) < 0) 
		{
            cli_app_log(CLI_LOG_ERROR, 
						"decrypt faild fd == %d, len %d\n", 
						fd, rcv);
            rcv = -1;
        }
        else 
        {
            if (out_len > 0)
            {
                *data = buf_out;
                buf_out[out_len] = 0;
            }
            else
            {
                cli_app_log(CLI_LOG_WARNING, "decrypt len is %d \n", out_len);
            }
        }
    }
    else 
    {
        if (rcv > 0)
        {
            if (strcmp(dev_conf.dev.protocol, CAIPIN) == 0 || strcmp(dev_conf.dev.protocol, ZHIHUI) == 0 
                || strcmp(dev_conf.dev.protocol, KUANGUANG) == 0 || strcmp(dev_conf.dev.protocol, CAIPINNEW) == 0 
                || strcmp(dev_conf.dev.protocol, HUANSHUO) == 0 || strcmp(dev_conf.dev.protocol, WANGXUN) == 0
                || strcmp(dev_conf.dev.protocol, RENZIXING) == 0|| strcmp(dev_conf.dev.protocol, FENGHUO) == 0
                || strcmp(dev_conf.dev.protocol, JINFENG) == 0 || strcmp(dev_conf.dev.protocol, GAOKE) == 0
                || strcmp(dev_conf.dev.protocol, BAIZHUO) == 0 || strcmp(dev_conf.dev.protocol, LOCATION) == 0
                || strcmp(dev_conf.dev.protocol, ZISHUO) == 0)

            {
                memcpy(buf_out, buf, rcv);
		        out_len = rcv;
            }
            else if (strcmp(dev_conf.dev.protocol, LEGU) == 0)
            {
                cli_app_log(CLI_LOG_INFO, "rcv msg len is %d \n", rcv);
                handleMsgFromLeGuServer( buf, rcv, buf_out, (ssize_t *)&out_len);
            }
            else if (strcmp(dev_conf.dev.protocol, ZHONGDUN) == 0)
            {
                cli_app_log(CLI_LOG_INFO, "rcv msg len is %d sock is %d\n", rcv, fd);
                if (fd == sock_mng)
                    handleMsgFromZhongdunXa(IF_APP_EVENT_MNG_SERVER ,buf, rcv, buf_out, (ssize_t *)&out_len);
                else
                    handleMsgFromZhongdunXa(IF_APP_EVENT_DATA_SERVER ,buf, rcv, buf_out, (ssize_t *)&out_len);

            }
			else if(strcmp(dev_conf.dev.protocol, XINAN) == 0)
			{
/*
                U16 len1 =htons(5);
                memcpy(buf, XINAN_MESSAGE_HEADER_START, 4);
                memcpy(buf + 4, XINAN_MESSAGE_BODY_HASH, 1);
                memcpy(buf + 5, &len1, 2);
                memcpy(buf + 7, XINAN_MESSAGE_BODY_HASH, 1);

                //memcpy(buf + 8, "02533#460029204531088", 21);
                memcpy(buf + 8, "02531", 5);
                rcv = 13;
                	cli_set_mng_status(MNG_SERVER_STATUS_CONNECTED);*/
                handleMsgFromXinanServer( buf, rcv, buf_out, (ssize_t *)&out_len);			   
			}
            *data = buf_out;
            buf_out[out_len] = 0;
       }
	}

    buffer_free(buf);
    if (rcv <= 0) 
    {
        cli_app_log(CLI_LOG_CRITICAL, 
					"read from %d, len is %d\n", 
					fd, rcv);
        buffer_free(buf_out);
        if (fd == sock_mng)
        {	
            cli_destroy_tcp_socket(sock_mng);
            event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_ERR_MNG, 0,  NULL);
        }
		else
		{
            cli_destroy_tcp_socket(sock_data);
            event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_ERR_DATA, 0,  NULL);
		}
        return rcv;
    }

    if (out_len <= 0)
    {
        buffer_free(buf_out);
        cli_app_log(CLI_LOG_DEFAULT, "can not converison msg \n");

    }

    return out_len;
}

static I32 cli_reset_fdset(fd_set * cli_set)
{
    I32 max;

    FD_ZERO(cli_set);
    if (sock_data != -1) 
	{
        FD_SET(sock_data, cli_set);
    }
	
    if (sock_mng != -1) 
	{
        FD_SET(sock_mng, cli_set);
    }

	if (sock_data > sock_mng)	
	{
		max = sock_data;
	} 
	else
	{

		max = sock_mng;
	}
	
    return max;
}

void setCliThreadOk()
{
    pthread_mutex_lock(&cli_mutex);
    cliThreadIsOk = true;
    pthread_mutex_unlock(&cli_mutex);
}

bool GetCliThreadStat()
{
    bool alive = false;
    pthread_mutex_lock(&cli_mutex);
    alive = cliThreadIsOk;
    cliThreadIsOk = false;
    pthread_mutex_unlock(&cli_mutex);
    return alive;
}

static void *cli_rcv_thread(void *args)
{
    pthread_setname_np(pthread_self(), "cli_rcv_thread");
  //  signal(SIGPIPE, SIG_IGN);
    fd_set cli_set;
    struct timeval cli_tv;
    I32 max, tmp, len;
    I8 *data, *buf;
    I32 val;
    socklen_t opt_len;
    I32 ret = IF_APP_OK;
    cli_tv.tv_usec = 500;
    cli_tv.tv_sec = 0;
    max = 0;
	bufSnd = malloc(65535);
    memset(bufSnd, 0, 65535);
    pthread_mutex_init(&cli_mutex, NULL);    
    while (1)
	{
        //check if we need re-crate channel.
        setCliThreadOk();// here to set thread ok
#ifdef MODULE_TEST
        if ( testCliThread )
        {
           cli_app_log(CLI_LOG_INFO, "----- test module %s --------\n", cli_rcv_thread);
            while(1)
            {
            }
        }
#endif 
        if (cli_get_mng_status() == MNG_SERVER_STATUS_CONNECTING) 
		{
            ret = cli_init(&dev_conf, MNG_SERVER_STATUS_CONNECTING);
            if ( ret != IF_APP_OK) 
			{	
                if ( ret != IF_APP_CONNECT_REFUSED )
                    event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_ERR_MNG, 0, NULL);
                else if (strcmp(dev_conf.dev.protocol, ZHONGDUN) == 0)
                    event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_MNG_REFUSED, 0, NULL);
                else
                    event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_CONNECT_REFUSED, 0, NULL);
                cli_set_mng_status(MNG_SERVER_STATUS_DISCONNECTED);
                continue;
            } 
			else 
			{
                cli_set_mng_status(MNG_SERVER_STATUS_WAITING_WELCOME);
                cli_app_log(CLI_LOG_INFO, "waitting for welcome msg \n");
                if (strcmp(dev_conf.dev.protocol, LEGU) == 0 ||
					strcmp(dev_conf.dev.protocol, XINAN) == 0 ||
                    strcmp(dev_conf.dev.protocol, ZHONGDUN) == 0 )
                {
                    buf = buffer_allocate();
                    if (buf == NULL)
                    {
                        cli_app_log(CLI_LOG_ERROR, "can not allocate buffer \n");
                    }
                    len = sprintf(buf, "%s", "Welecome to tcp server!");
                    cli_app_log(CLI_LOG_INFO, "create welecome msg len %d\n", len);
                    event_queue_add(IF_APP_EVENT_INIT_CLI, sock_mng, len, buf);                                      
                }                
            }
        }

        if (cli_get_data_status() == DATA_SERVER_STATUS_CONNECTING) 
		{
			ret = cli_init(&dev_conf, DATA_SERVER_STATUS_CONNECTING);
            if ( ret != IF_APP_OK) 
			{
				if ( ret != IF_APP_CONNECT_REFUSED  )
                    event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_ERR_DATA, 0, NULL);
                else if (strcmp(dev_conf.dev.protocol, ZHONGDUN) == 0)
                    event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_DATA_REFUSED, 0, NULL);
                else
                    event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_CONNECT_REFUSED, 0, NULL);
                cli_set_data_status(DATA_SERVER_STATUS_DISCONNECTED);

                //clear created socket
                if (strcmp(dev_conf.dev.protocol, ZHONGDUN) != 0)
                    cli_destroy_tcp_socket(CLI_TO_SRV_ALL_MASK);
				
                continue;
            } 
			else 
			{
                cli_set_data_status(DATA_SERVER_STATUS_WAITING_WELCOME);
                cli_app_log(CLI_LOG_INFO, "waitting for welcome msg \n");
                if (strcmp(dev_conf.dev.protocol, ZHONGDUN) == 0 || 
                    strcmp(dev_conf.dev.protocol, NANFEI) == 0) 
                {
                    buf = buffer_allocate();
                    if (buf == NULL)
                    {
                        cli_app_log(CLI_LOG_ERROR, "can not allocate buffer \n");
                    }
                    len = sprintf(buf, "%s", "Welecome to tcp server!");
                    cli_app_log(CLI_LOG_INFO, "create welecome msg len %d\n", len);
                    event_queue_add(IF_APP_EVENT_INIT_CLI, sock_data, len, buf);                                      
                }  
            }
        }

        max = cli_reset_fdset(&cli_set);
        if (max < 0) 
		{
            usleep(100000);
            continue;
        }
		
        cli_tv.tv_usec = 50000;
        tmp = select(max + 1, &cli_set, NULL, NULL, &cli_tv);
        if (tmp < 0) 
		{
            //should not be here, because if remote closed socket, select will return and then
            //read to socket will be 0, then it can close the socket.
            //
            //if send error, it will close the socket, then there might be to event sent to main thread.
            // need to sure it. I still want rcv thread to check errors.
	
            if (sock_data != -1 && getsockopt(sock_data, SOL_SOCKET, SO_RCVBUF, &val,&opt_len) < 0) 
			{
                cli_destroy_tcp_socket(sock_data);
                event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_ERR_DATA, 0, NULL);
            }
			
            if (sock_mng != -1 && getsockopt(sock_mng, SOL_SOCKET, SO_RCVBUF, &val, &opt_len) < 0) 
			{
                cli_destroy_tcp_socket(sock_mng);
                event_queue_add(IF_APP_EVENT_CLI_STOP, CLI_SOCK_ERR_MNG, 0,  NULL);
            }

            continue;
        }

        if (tmp == 0) 
		{
            continue;
        }

        if ((sock_data != -1) && FD_ISSET(sock_data, &cli_set)) 
		{
            len = rcv_from_tcp(sock_data, &data);
            if (len > 0) 
			{
                if (cli_get_data_status() == DATA_SERVER_STATUS_CONNECTED) 
                {
                    buf = buffer_allocate();
                    if (buf == NULL) 
                    {
                        cli_app_log(CLI_LOG_CRITICAL, 
									"get buffer fail\n");
                        return 0;
                    }	
                    if ((disable_auth == 0) || (disable_auth == 2))
                    {
                    	len = cli_decompress_data(data, len, buf);
   	                    buffer_free(data);
                        data = buf;
                    }
                    else
                    {
                        memcpy(buf, data, len);
                        buffer_free(data);
                        data = buf;
                    }

                    if (len > 0) 
                    {
                        event_queue_add(IF_APP_EVENT_DATA_SERVER, sock_data, len, data);
                    } 
                    else 
                    {
                        buffer_free(buf);
                    }
                } 
                else 
                {
                    if((strstr(data, "Welecome") == NULL) && ((disable_auth == 0) || (disable_auth == 2)) && (strstr(data, "Welcome") == NULL))
                    { 
                        buf = buffer_allocate();
                        if (buf == NULL) 
                        {
                    	    cli_app_log(CLI_LOG_CRITICAL, 
										"get buffer fail\n");
                     	    return 0;
                   		}	
                        len = cli_decompress_data(data, len, buf);

                        buffer_free(data);
                        data = buf;
                        event_queue_add(IF_APP_EVENT_INIT_CLI, sock_data, len, data);
                    }
                    else
                    {
                        event_queue_add(IF_APP_EVENT_INIT_CLI, sock_data, len, data);
                    }              
                }
            }
        }

        if ((sock_mng != -1) && FD_ISSET(sock_mng, &cli_set)) 
        {
            len = rcv_from_tcp(sock_mng, &data);
            if (len > 0) 
            {
                if (cli_get_mng_status() == MNG_SERVER_STATUS_CONNECTED) 
                {
                    event_queue_add(IF_APP_EVENT_MNG_SERVER, sock_mng, len, data);                  
                } 
				else 
                {
                    event_queue_add(IF_APP_EVENT_INIT_CLI, sock_mng, len, data);
                }
            }     
        }
    }

    return NULL;
}

I32 cli_init(DEV_CONF * conf, U32 step)
{
    SRV_INFO *srv;
    I32 ret = IF_APP_OK;
    disable_auth =  atoi(dev_conf.auth.disable_auth);
    if (strlen(conf->auth.addr) == 0 || strlen(conf->mng.addr) == 0 || strlen(conf->data.addr) == 0) {
        cli_app_log(CLI_LOG_CRITICAL,
                    "Cli init error: one of server is NULL\n");
		
        event_queue_add(IF_APP_EVENT_CLI_STOP, 0, 0, NULL);
        return -1;
    }

	if (step == MNG_SERVER_STATUS_CONNECTING) 
	{
        srv = &conf->mng;
        ret = cli_create_tcp_socket_to(CLI_TCP_CONN_TIMEOUT, CLI_SRV_MNG, srv->addr, atoi(srv->port));
        if (sock_mng == -1 ) 
		{
            if (ret  != IF_APP_CONNECT_REFUSED )           
                return IF_APP_ERROR;
            else 
                return IF_APP_CONNECT_REFUSED ;
        }

    } 
	else if (step == DATA_SERVER_STATUS_CONNECTING) 
	{
        srv = &conf->data;
        cli_create_tcp_socket_to(CLI_TCP_CONN_TIMEOUT, CLI_SRV_DATA, srv->addr, atoi(srv->port));
        if (sock_data == -1) 
		{
            if (ret  != IF_APP_CONNECT_REFUSED )           
                return IF_APP_ERROR;
            else 
                return IF_APP_CONNECT_REFUSED ;
        }
    } 
	else if (step == CLI_THREAD_CREATING) 
	{
        if (pthread_create(&cli_thread, NULL, cli_rcv_thread, NULL) != 0) 
		{
            cli_app_log(CLI_LOG_CRITICAL,
                        "ERROR: Can't create cli receive thread\n");

            return IF_APP_ERROR;
        }

    }
	
    return IF_APP_OK;
}

static void *cli_udp_rcv_thread(void *args)
{
    pthread_setname_np(pthread_self(), "cli_udp_thread");
    fd_set rfds;
    int ret = 0, bytes = 0;
    I8 *data = NULL;
    I8 *bufTmp = NULL;
    struct timeval tmVal;
    tmVal.tv_usec = 0;
    tmVal.tv_sec = 1;
    struct sockaddr_in server_addr;
    socklen_t socklen = sizeof(struct sockaddr_in);
    while(1)
    {
        FD_ZERO(&rfds);
        FD_SET(udpSock, &rfds);
        tmVal.tv_usec = 0;
        tmVal.tv_sec = 2;
        do
        {
            ret = select(udpSock + 1, &rfds, NULL, NULL, &tmVal);
        } while (ret < 0 && errno == EINTR);
        
        if (ret == 0)
        {
            continue;
        }
        if (FD_ISSET(udpSock, &rfds))
        {
            data = buffer_allocate();
            if (data == NULL) 
            {
                cli_app_log(CLI_LOG_CRITICAL, 
                        "get buffer fail\n");
                return 0;
            }	
            do 
            {
                bytes = recvfrom(udpSock, data, 1024, 0, (struct sockaddr *)&server_addr, &socklen);
            } while(bytes == -1 && (errno == EINTR));
            cli_app_log(CLI_LOG_INFO, "recv udp data %s \n", data);
            if (bytes > 0)
            {
                if (strcmp(dev_conf.dev.protocol, NANFEI) == 0)
                {
                    bufTmp = buffer_allocate();
                    if (bufTmp == NULL) 
                    {
                        cli_app_log(CLI_LOG_CRITICAL, 
                                "get buffer fail\n");
                        return 0;
                    }
                    int inLen = 0;
                    handleMsgFromNanfei(data, bytes, bufTmp, &inLen);
                    bytes = inLen;
                    buffer_free(data);
                    data = NULL;
                    data = bufTmp;
                }
                
                event_queue_add(IF_APP_EVENT_UDP_SERVER, udpSock, bytes, data);
            }
            else
            {
                buffer_free(data);
            }
            data = NULL;
        }

    }


}



I32 initUdpthread()
{
    udpSock = socket(AF_INET, SOCK_DGRAM, 0);
    if (udpSock == -1)
    {
        cli_app_log(CLI_LOG_NOTICE, "can not create udp socket\n");
        return -1;
    }
    char mac[20] = {0};
    getmac(eth1Mac, mac);
    I32 fnctl_tmp;
    fnctl_tmp = fcntl(udpSock, F_GETFL);
    fcntl(udpSock, F_SETFL, fnctl_tmp | O_NONBLOCK);
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    if (strcmp(dev_conf.dev.protocol, BAIZHUO) == 0)
        server_addr.sin_port = htons(18050);
    else
        server_addr.sin_port = htons(atoi(dev_conf.mng.open_port));
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(udpSock, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_in)) == -1)
    {
        cli_app_log(CLI_LOG_WARNING, "bind udp socket failed \n");
        return -1;
    }

    if (pthread_create(&cli_udp_thread, NULL, cli_udp_rcv_thread, NULL) != 0) 
     {
        cli_app_log(CLI_LOG_WARNING, "can not create udp thread\n");
        return -1;
     }
     return IF_APP_OK;
}

I32 sendHeartBeat(I32 port, const I8 *buf, I32 bufLen)
{
    if (udpSock == -1)
    {

        udpSock = socket(AF_INET, SOCK_DGRAM, 0);
        if (udpSock == -1)
        {
            cli_app_log(CLI_LOG_NOTICE, "can not create udp socket\n");
            return -1;
        }

        I32 fnctl_tmp;
        fnctl_tmp = fcntl(udpSock, F_GETFL);
        fcntl(udpSock, F_SETFL, fnctl_tmp | O_NONBLOCK);

    }
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    if (strcmp(dev_conf.dev.protocol, BAIZHUO) == 0)
    {
        server_addr.sin_addr.s_addr = inet_addr(dev_conf.auth.addr);
    }
    else
    {
        server_addr.sin_addr.s_addr = inet_addr(dev_conf.mng.addr);
    }
    int send_rc = -1;
    socklen_t len = sizeof(server_addr);
    cli_app_log(CLI_LOG_INFO, "cli_log send udp port %d addr %s  %s len is %d\n", port, dev_conf.mng.addr, buf, bufLen);
    do
    {
        send_rc = sendto(udpSock, buf, bufLen, 0, (struct sockaddr *)&server_addr, len);
    }
    while ( (send_rc == -1) && (errno == EINTR) );

    if( send_rc>=0 )
    {
        cli_app_log(CLI_LOG_INFO, "send udp msg success \n");
        return IF_APP_OK;
    }
    else
    {
        cli_app_log(CLI_LOG_NOTICE, "send udp msg failed, msg len %d\n", bufLen);
        return IF_APP_ERROR;
    }

}

I32 sendBaiZhuoHb()
{
    I8 buf[128] = {0};
    I32 len = 0;
    len = sprintf(buf, "%s", dev_conf.ftp.ftpbsic);
    sendHeartBeat(18060, buf, len);
    return 0;
}

static const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char * base64_encode( const unsigned char * bindata, char * base64, int binlength )
{
    int i, j;
    unsigned char current;

    for ( i = 0, j = 0 ; i < binlength ; i += 3 )
    {
        current = (bindata[i] >> 2) ;
        current &= (unsigned char)0x3F;
        base64[j++] = base64char[(int)current];

        current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ;
        if ( i + 1 >= binlength )
        {
            base64[j++] = base64char[(int)current];
            base64[j++] = '=';
            base64[j++] = '=';
            break;
        }
        current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F );
        base64[j++] = base64char[(int)current];

        current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ;
        if ( i + 2 >= binlength )
        {
            base64[j++] = base64char[(int)current];
            base64[j++] = '=';
            break;
        }
        current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 );
        base64[j++] = base64char[(int)current];

        current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ;
        base64[j++] = base64char[(int)current];
    }
    base64[j] = '\0';
    return base64;
}

static int base64_decode( const char * base64, unsigned char * bindata )
{
    int i, j;
    unsigned char k;
    unsigned char temp[4];
    for ( i = 0, j = 0; base64[i] != '\0' ; i += 4 )
    {
        memset( temp, 0xFF, sizeof(temp) );
        for ( k = 0 ; k < 64 ; k ++ )
        {
            if ( base64char[k] == base64[i] )
                temp[0]= k;
        }
        for ( k = 0 ; k < 64 ; k ++ )
        {
            if ( base64char[k] == base64[i+1] )
                temp[1]= k;
        }
        for ( k = 0 ; k < 64 ; k ++ )
        {
            if ( base64char[k] == base64[i+2] )
                temp[2]= k;
        }
        for ( k = 0 ; k < 64 ; k ++ )
        {
            if ( base64char[k] == base64[i+3] )
                temp[3]= k;
        }

        bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] << 2))&0xFC)) |
                ((unsigned char)((unsigned char)(temp[1]>>4)&0x03));
        if ( base64[i+2] == '=' )
            break;

        bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) |
                ((unsigned char)((unsigned char)(temp[2]>>2)&0x0F));
        if ( base64[i+3] == '=' )
            break;

        bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) |
                ((unsigned char)(temp[3]&0x3F));
    }
    return j;
}

/************************************************************************
 * DES-CBC加密方式
 * 8位密钥，加密内容8位补齐，补齐方式为：PKCS7。
 *
 * file: test_des_cbc.c
 * gcc -Wall -O2 -o test_des_cbc test_des_cbc.c hex.c -lcrypto
 *
 ************************************************************************/
static void packBaiZhuoData(const char *data, char *buf, int len)
{
    DES_key_schedule ks;
    DES_cblock ivec;
    memcpy(&ivec, dev_conf.ftp.ftpIV, 8);
    DES_set_key_unchecked((const_DES_cblock *)dev_conf.ftp.ftpKey, &ks);
    I32 len8Byte = (len/8 + 1) * 8;
    unsigned char perdata[len8Byte];
    unsigned char encrydata[len8Byte];

    memset(perdata, (8 - len%8), len8Byte);
    memset(encrydata, 0, len8Byte);
    memcpy(perdata, data, len);
    cli_app_log(CLI_LOG_INFO, "perdata : %s %d  %d %s %s \n", perdata, len, len8Byte, dev_conf.ftp.ftpKey, dev_conf.ftp.ftpIV);
    DES_ncbc_encrypt(perdata, encrydata, len8Byte, &ks, &ivec, DES_ENCRYPT);  
    
    memset(buf, 0, 2 *len);
    base64_encode(encrydata, buf, len8Byte);
    cli_app_log(CLI_LOG_DEFAULT, "data : %s  perdata %s encodedata %s \n", data, perdata, buf);

}



I32 sendDataByUdp(I8 *imsi, I8 *imei, I8 *time)
{
    int len3 = 0;
    char data[256] = {0};
    memcpy(data, "1.1.1", strlen( "1.1.1"));
    len3 += strlen("1.1.1");
    data[len3++] = 1;  //1

    memcpy(data +len3, "42", 2);
    len3 += 2;
    data[len3++] = 1; //2

    memcpy(data + len3, "4.3.3", 5);
    len3 += 5;
    data[len3++] = 1; //3

    memcpy(data + len3, eth1Mac, strlen(eth1Mac));
    len3 += strlen(eth1Mac);
    data[len3++] = 1; //4

    data[len3++] = 1; //5

    data[len3++] = 1; //6

    memcpy(data + len3, time, strlen(time));
    len3 += strlen(time);
    data[len3++] = 1; //7

    //memcpy(data + len3, "-22", 3);
    //len3 += 3;
    data[len3++] = 1; //8

    data[len3++] = 1; //9

    data[len3++] = 1; //10

    data[len3++] = 1; //11

    data[len3++] = 1; //12

    data[len3++] = 1; //13;

    data[len3++] = 1; //14

    data[len3++] = 1; //15

    data[len3++] = 1; //16

    memcpy(data + len3, dev_conf.ftp.ftpDataSource, strlen( dev_conf.ftp.ftpDataSource));
    len3 += strlen( dev_conf.ftp.ftpDataSource);
    data[len3++] = 1; //17

    memcpy(data + len3, dev_conf.ftp.ftpbsic, strlen(dev_conf.ftp.ftpbsic));
    len3 += strlen(dev_conf.ftp.ftpbsic);
    data[len3++] = 1; //18;

    memcpy(data + len3, dev_conf.dev.pos_lo, strlen(dev_conf.dev.pos_lo));
    len3 += strlen(dev_conf.dev.pos_lo);
    data[len3++] = 1;//19

    memcpy(data + len3, dev_conf.dev.pos_la, strlen(dev_conf.dev.pos_la));
    len3 += strlen(dev_conf.dev.pos_la);
    data[len3++] = 1; //20

    memcpy(data +len3, "136", 3);
    len3 += 3;
    data[len3++] = 1; //21
    
    data[len3++] = 1; // 22
     
    data[len3++] = 1;//23

    data[len3++] = 1; //24

    data[len3++] = 1; //25

    memcpy(data + len3, imsi, strlen(imsi));
    len3 += strlen(imsi);
    data[len3++] = 1; //26
    
    if (strlen(dev_conf.ftp.ftpDataSource) > 8)
    {
        data[len3++] = dev_conf.ftp.ftpDataSource[7];
    }
    data[len3++] = 1; //27

    data[len3++] = dev_conf.dev.pos_he[0];
    data[len3++] = 1; // 28

    data[len3++] = '0';
    data[len3++] = 1; //29

    data[len3++] = 1; // 30

    data[len3++] = 1; // 31

    data[len3++] = 1; //32

    data[len3++] = 2;

    char buf[len3 * 2];
    packBaiZhuoData(data, buf, len3);
    sendHeartBeat(atoi(dev_conf.auth.port), buf, strlen(buf));
    return 0;
}

void sendMacDataByUdp(I8 *mac, I8 *time)
{
    int len3 = 0;
    char data[256] = {0};
    memcpy(data, "1.1.1", strlen( "1.1.1"));
    len3 += strlen("1.1.1");
    data[len3++] = 1;  //1

    memcpy(data +len3, "42", 2);
    len3 += 2;
    data[len3++] = 1; //2

    memcpy(data + len3, "4.3.3", 5);
    len3 += 5;
    data[len3++] = 1; //3

    memcpy(data + len3, mac, strlen(mac));
    len3 += strlen(mac);
    data[len3++] = 1; //4

    data[len3++] = 1; //5

    data[len3++] = 1; //6

    memcpy(data + len3, time, strlen(time));
    len3 += strlen(time);
    data[len3++] = 1; //7

    //memcpy(data + len3, "-22", 3);
    //len3 += 3;
    data[len3++] = 1; //8

    data[len3++] = 1; //9

    data[len3++] = 1; //10

    data[len3++] = 1; //11

    data[len3++] = 1; //12

    data[len3++] = 1; //13;

    data[len3++] = 1; //14

    data[len3++] = 1; //15

    data[len3++] = 1; //16

    memcpy(data + len3, dev_conf.ftp.ftpDataSource, strlen( dev_conf.ftp.ftpDataSource));
    len3 += strlen( dev_conf.ftp.ftpDataSource);
    data[len3++] = 1; //17

    memcpy(data + len3, dev_conf.ftp.ftpbsic, strlen(dev_conf.ftp.ftpbsic));
    len3 += strlen(dev_conf.ftp.ftpbsic);
    data[len3++] = 1; //18;

    memcpy(data + len3, dev_conf.dev.pos_lo, strlen(dev_conf.dev.pos_lo));
    len3 += strlen(dev_conf.dev.pos_lo);
    data[len3++] = 1;//19

    memcpy(data + len3, dev_conf.dev.pos_la, strlen(dev_conf.dev.pos_la));
    len3 += strlen(dev_conf.dev.pos_la);
    data[len3++] = 1; //20

    memcpy(data +len3, "136", 3);
    len3 += 3;
    data[len3++] = 1; //21
    
    data[len3++] = 1; // 22
     
    data[len3++] = 1;//23

    data[len3++] = 1; //24

    data[len3++] = 1; //25

  //  memcpy(data + len3, imsi, strlen(imsi));
  //  len3 += strlen(imsi);
    data[len3++] = 1; //26
    
    if (strlen(dev_conf.ftp.ftpDataSource) > 8)
    {
        data[len3++] = dev_conf.ftp.ftpDataSource[7];
    }
    data[len3++] = 1; //27

    data[len3++] = dev_conf.dev.pos_he[0];
    data[len3++] = 1; // 28

    data[len3++] = '0';
    data[len3++] = 1; //29

    data[len3++] = 1; // 30

    data[len3++] = 1; // 31

    data[len3++] = 1; //32

    data[len3++] = 2;

    char buf[len3 * 2];
    packBaiZhuoData(data, buf, len3);
    sendHeartBeat(atoi(dev_conf.auth.port), buf, strlen(buf));
}

I32 cli_exit(void)
{
    pthread_cancel(cli_thread);
    pthread_join(cli_thread, NULL);

    if (sock_mng != -1) 
	{
        cli_destroy_tcp_socket(sock_mng);
    }
	
    if (sock_data != -1) {
        cli_destroy_tcp_socket(sock_data);
    }
	
    return 0;
}

I32 getSock(bool isMng)
{
    if (isMng)
        return sock_mng;
    else
        return sock_data;
}

#ifdef IF_APP_UNIT_TEST

I32 cli_gen_test_ctrl_string(I8 * buf, I32 code)
{
    I32 len;

    len = sprintf(buf, "{\"type\":%d,\"code\":%d}", CMD_CTRL, code);
    return len;
}
#endif
